package com.employee.util;

import com.employee.entity.Column;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ResultSetMapper {
    
    public static <T> List<T> map(ResultSet rs, Class<T> clazz) throws SQLException, ReflectiveOperationException {
        List<T> resultList = new ArrayList<>();
        
        if (rs == null || clazz == null) {
            return resultList;
        }
        
        ResultSetMetaData metaData = rs.getMetaData();
        int columnCount = metaData.getColumnCount();
        
        Map<String, Integer> columnIndexMap = new HashMap<>();
        for (int i = 1; i <= columnCount; i++) {
            String columnLabel = metaData.getColumnLabel(i);
            columnIndexMap.put(columnLabel.toLowerCase(), i);
        }
        
        Field[] fields = clazz.getDeclaredFields();
        
        while (rs.next()) {
            T instance = clazz.getDeclaredConstructor().newInstance();
            
            for (Field field : fields) {
                if (field.isAnnotationPresent(Column.class)) {
                    Column column = field.getAnnotation(Column.class);
                    String columnName = column.value().toLowerCase();
                    
                    if (columnIndexMap.containsKey(columnName)) {
                        field.setAccessible(true);
                        Object value = getColumnValue(rs, columnName, field.getType());
                        if (value != null) {
                            field.set(instance, value);
                        }
                    }
                }
            }
            
            resultList.add(instance);
        }
        
        return resultList;
    }
    
    private static Object getColumnValue(ResultSet rs, String columnName, Class<?> fieldType) throws SQLException {
        Object value = null;
        
        try {
            if (fieldType == String.class) {
                value = rs.getString(columnName);
            } else if (fieldType == Integer.class || fieldType == int.class) {
                int intValue = rs.getInt(columnName);
                if (!rs.wasNull()) {
                    value = intValue;
                }
            } else if (fieldType == Long.class || fieldType == long.class) {
                long longValue = rs.getLong(columnName);
                if (!rs.wasNull()) {
                    value = longValue;
                }
            } else if (fieldType == Double.class || fieldType == double.class) {
                double doubleValue = rs.getDouble(columnName);
                if (!rs.wasNull()) {
                    value = doubleValue;
                }
            } else if (fieldType == Date.class) {
                java.sql.Timestamp timestamp = rs.getTimestamp(columnName);
                if (timestamp != null) {
                    value = new Date(timestamp.getTime());
                }
            } else if (fieldType == BigDecimal.class) {
                value = rs.getBigDecimal(columnName);
            } else {
                value = rs.getObject(columnName);
            }
        } catch (SQLException e) {
            System.err.println("Error mapping column " + columnName + ": " + e.getMessage());
        }
        
        return value;
    }
    
    public static <T> T mapOne(ResultSet rs, Class<T> clazz) {
        try {
            List<T> list = map(rs, clazz);
            return list.isEmpty() ? null : list.get(0);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
